package com.eight.cloud.payment.core.wechat.mode;


import cn.hutool.core.bean.BeanUtil;
import com.eight.cloud.client.model.dto.PlatformOrderDto;
import com.eight.cloud.client.model.vo.OrderVo;
import com.eight.cloud.core.utils.format.ObjectFormat;
import com.eight.cloud.payment.common.enums.PayStrategyEnum;
import com.eight.cloud.payment.config.WechatServiceProviderConfig;
import com.eight.cloud.payment.core.wechat.channel.WxPay;
import com.eight.cloud.payment.entity.SubPayOrderEntity;
import com.eight.cloud.payment.model.vo.MerchantAppVo;
import com.eight.cloud.payment.model.vo.SubPayOrderVo;
import com.eight.cloud.payment.service.IMerchantAppService;
import com.eight.cloud.payment.service.ISubPayOrderService;
import com.eight.cloud.payment.service.partnerpayments.wxcodepay.CodePayService;
import com.eight.cloud.payment.service.partnerpayments.wxcodepay.model.*;
import com.eight.cloud.redisson.utils.RedisUtils;
import com.eight.cloud.springmvc.utils.thread.IncreasingIntervalScheduler;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import static com.eight.cloud.core.global.constant.NumConstant.FIVE;
import static com.eight.cloud.core.global.constant.NumConstant.TEN;

/**
 * 付款码支付
 *
 * @ClassName: WxCodePay
 * @Author: TXC
 * @Date: 2024-11-29 18:02
 **/
@Service
public class WxCodePay extends WxPay {
    private static final Logger log = LoggerFactory.getLogger(WxCodePay.class);
    private final WechatServiceProviderConfig wechatServiceProviderConfig;
    private final CodePayService codePayService;
    private final ISubPayOrderService subPayOrderService;


    public WxCodePay(RSAAutoCertificateConfig rsaAutoCertificateConfig,
                     WechatServiceProviderConfig wechatServiceProviderConfig, RedisUtils redisUtils,
                     ISubPayOrderService subPayOrderService, IMerchantAppService merchantAppService) {
        super(rsaAutoCertificateConfig, wechatServiceProviderConfig, redisUtils, merchantAppService);
        this.wechatServiceProviderConfig = wechatServiceProviderConfig;
        this.codePayService = new CodePayService.Builder().config(rsaAutoCertificateConfig).build();
        this.subPayOrderService = subPayOrderService;
    }

    @Override
    public String pay(PlatformOrderDto order) {
        MerchantAppVo merchantApp = getAccount(order.getSubMerchantId());
        PrepayRequest prepayRequest = new PrepayRequest();
        prepayRequest.setSpMchid(wechatServiceProviderConfig.getMerchantId());
        prepayRequest.setSpAppid(wechatServiceProviderConfig.getAppid());
        prepayRequest.setDescription(order.getTitle());
        prepayRequest.setOutTradeNo(order.getUuid());
        prepayRequest.setSubAppid(merchantApp.getSubAppid());
        prepayRequest.setSubMchid(order.getSubMerchantId());
        Amount amount = new Amount();
        amount.setTotal(Integer.valueOf(order.getPriceFen()));
        amount.setCurrency("CNY");
        prepayRequest.setAmount(amount);
        Payer payer = new Payer();
        payer.setAuthCode(order.getAuthCode());
        prepayRequest.setPayer(payer);
        SceneInfo sceneInfo = new SceneInfo();
        StoreInfo storeInfo = new StoreInfo();
        storeInfo.setOutId(order.getAppid());
        sceneInfo.setStoreInfo(storeInfo);
        prepayRequest.setSceneInfo(sceneInfo);
        PrepayResponse prepayResponse = codePayService.prepay(prepayRequest);
        if (PrepayResponse.TradeStateEnum.SUCCESS.equals(prepayResponse.getTradeState())) {
            subPayOrderService.updateSubPayOrder(order.getUuid(), prepayResponse.getTransactionId(),
                    SubPayOrderEntity.PayStatusEnum.PAID.getValue());
        } else {
            new IncreasingIntervalScheduler.Builder().setMaxExecutions(FIVE)
                    .setInitialInterval(TEN).setIncreasingInterval(TEN)
                    .setCallSupplier(() -> checkTradeState(prepayResponse)).build().start();
        }
        prepayResponse.setOutTradeNo(order.getOutTradeNo());
        log.info("付款码支付结果 {}", prepayResponse);
        return ObjectFormat.objectToStr(prepayResponse);
    }

    @Override
    public OrderVo queryOrderById(SubPayOrderVo subPayOrder) {
        QueryOrderByIdRequest request = new QueryOrderByIdRequest();
        request.setTransactionId(subPayOrder.getTransactionId());
        request.setSpMchid(wechatServiceProviderConfig.getMerchantId());
        request.setSubMchid(subPayOrder.getMerchantId());
        Transaction transaction = codePayService.queryOrderById(request);
        OrderVo orderVo = new OrderVo();
        BeanUtil.copyProperties(transaction, orderVo);
        if (transaction != null && transaction.getPayer() != null) {
            orderVo.setSubOpenid(transaction.getPayer().getSubOpenid());
        } else {
            orderVo.setSubOpenid(null);
        }
        return orderVo;
    }

    @Override
    public OrderVo queryOrderByOutTradeNo(SubPayOrderVo subPayOrder) {
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setOutTradeNo(subPayOrder.getUuid());
        request.setSpMchid(wechatServiceProviderConfig.getMerchantId());
        request.setSubMchid(subPayOrder.getMerchantId());
        Transaction transaction = codePayService.queryOrderByOutTradeNo(request);
        OrderVo orderVo = new OrderVo();
        BeanUtil.copyProperties(transaction, orderVo);
        if (transaction != null && transaction.getPayer() != null) {
            orderVo.setSubOpenid(transaction.getPayer().getSubOpenid());
        } else {
            orderVo.setSubOpenid(null);
        }
        orderVo.setOutTradeNo(subPayOrder.getSubOrderId());
        return orderVo;
    }

    @Override
    public String closeOrder(SubPayOrderVo subPayOrder) {
        CloseOrderRequest request = new CloseOrderRequest();
        request.setSpMchid(wechatServiceProviderConfig.getMerchantId());
        request.setSubMchid(subPayOrder.getMerchantId());
        request.setOutTradeNo(subPayOrder.getUuid());
        codePayService.closeOrder(request);
        subPayOrderService.updateSubPayOrder(subPayOrder.getUuid(), null, SubPayOrderEntity.PayStatusEnum.CLOSE.getValue());
        return null;
    }

    @Override
    public PayStrategyEnum getPayStrategy() {
        return PayStrategyEnum.WX_CODEPAY;
    }

    private boolean checkTradeState(PrepayResponse prepayResponse) {
        SubPayOrderVo subPayOrderVo = new SubPayOrderVo();
        subPayOrderVo.setUuid(prepayResponse.getOutTradeNo());
        subPayOrderVo.setMerchantId(prepayResponse.getSubMchid());
        subPayOrderVo.setSubOrderId(prepayResponse.getOutTradeNo());
        OrderVo orderVo = queryOrderByOutTradeNo(subPayOrderVo);
        log.info("付款码支付检查结果 {}", orderVo);
        if (OrderVo.TradeStateEnum.SUCCESS.equals(orderVo.getTradeState())) {
            subPayOrderService.updateSubPayOrder(subPayOrderVo.getUuid(), prepayResponse.getTransactionId(),
                    SubPayOrderEntity.PayStatusEnum.PAID.getValue());
            return true;
        } else if (OrderVo.TradeStateEnum.CLOSED.equals(orderVo.getTradeState())) {
            subPayOrderService.updateSubPayOrder(subPayOrderVo.getUuid(), prepayResponse.getTransactionId(),
                    SubPayOrderEntity.PayStatusEnum.CLOSE.getValue());
            return true;
        } else if (OrderVo.TradeStateEnum.USERPAYING.equals(orderVo.getTradeState())) {
            return false;
        }
        return false;
    }
}
